/*
 *  Copyright 2011-2012 Redia A/S
 * 
 *  This file is part of Redias Android Utilities.
 *
 *  Redias Android Utilities is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Redias Android Utilities is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with Redias Android Utilities.  If not, see <http://www.gnu.org/licenses/>.
 */
package dk.redia.lib.views;

import java.util.HashSet;
import java.util.Set;

import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.VideoView;
import dk.redia.R;
import dk.redia.lib.log.Log;

public class RediaVideoView extends RelativeLayout {
	private static final String logTag = "RediaVideoView";

	private static final int STATE_UI_ENABLED = 1;
	private static final int STATE_UI_DISABLED = 2;
	private static final int STATE_UI_ANIMATING = 3;

	private int state = STATE_UI_DISABLED;
	private VideoView videoView;
	private RelativeLayout navigationLayout;
	private RelativeLayout timelineLayout;
	
	private SeekBar timelineProgressBar;
	private TextView playedTimeTextView;
	private TextView remainingTimeTextView;
	private Button playButton;
	private Button fastForwardButton;
	private Button fastBackwardButton;
	private ProgressBar loadingProgressBar;
	
	private int uiMarginRight;
	private int uiMarginLeft;
	private int uiMarginTop = 70;
	private int uiMarginBottom = 70;
	
	private boolean squelchToggles = false;
	
	private Set<RediaVideoViewListener> listeners;
	
	
	public RediaVideoView(Context context) {
		super(context);
		init();
	}
	
	public RediaVideoView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	
	public RediaVideoView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}
	
/*	private void setUiMargin(int marginTop, int marginBottom, int marginRight, int marginLeft) {
		this.uiMarginBottom = marginBottom;
		this.uiMarginTop = marginTop;
		this.uiMarginRight = marginRight;
		this.uiMarginLeft = marginLeft;
	}*/
	
	public void addListener(RediaVideoViewListener listener) {
		listeners.add(listener);
	}
	
	public void removeListener(RediaVideoViewListener listener) {
		listeners.remove(listener);
	}
	
	private void notifyListenersUiFadeInStarted(Animation animation) {
		Set<RediaVideoViewListener> listenersCp = new HashSet<RediaVideoViewListener>(listeners);
		for (RediaVideoViewListener listener : listenersCp) {
			listener.uiFadeInStarted(animation);
		}
	}
	
	private void notifyListenersUiFadeOutStarted(Animation animation) {
		Set<RediaVideoViewListener> listenersCp = new HashSet<RediaVideoViewListener>(listeners);
		for (RediaVideoViewListener listener : listenersCp) {
			listener.uiFadeOutStarted(animation);
		}
	}
	
	private void notifyListenersPlaybackFinished() {
		Set<RediaVideoViewListener> listenersCp = new HashSet<RediaVideoViewListener>(listeners);
		for (RediaVideoViewListener listener : listenersCp) {
			listener.playbackFinished();
		}
	}
	
	private void notifyListenersPlaybackStarted() {
		Set<RediaVideoViewListener> listenersCp = new HashSet<RediaVideoViewListener>(listeners);
		for (RediaVideoViewListener listener : listenersCp) {
			listener.playbackStarted();
		}
	}
	
	private void init() {		
		listeners = new HashSet<RediaVideoViewListener>();
		navigationLayout = new RelativeLayout(getContext());
		timelineLayout = new RelativeLayout(getContext());
		videoView = new VideoView(getContext());
		fastForwardButton = new Button(getContext());
		fastBackwardButton = new Button(getContext());
		playButton = new Button(getContext());
		timelineProgressBar = new SeekBar(getContext(), null, android.R.attr.progressBarStyleHorizontal);
		playedTimeTextView = new TextView(getContext());
		remainingTimeTextView = new TextView(getContext());
		loadingProgressBar = new ProgressBar(getContext());
	
		// Loading progress bar
		RelativeLayout.LayoutParams loadingProgressBarLayoutParams = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT,
				RelativeLayout.LayoutParams.WRAP_CONTENT
		);
		loadingProgressBarLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, 1);
		
		// Navigation buttons
		// Play button
		RelativeLayout.LayoutParams playButtonLayoutParams = new RelativeLayout.LayoutParams(
				52,
				47
		);
//		playButtonLayoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL, true);
		playButtonLayoutParams.setMargins(20, 0, 20, 0);
		playButton.setBackgroundResource(R.drawable.play_button_drawable);
		playButton.setId(1);
		playButton.setVisibility(View.INVISIBLE);
		playButton.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {
				if (videoView.isPlaying()) {
					pause();
				} else {
					start();
				}
				
			}
		});
		playButtonLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, 1);
		navigationLayout.addView(playButton, playButtonLayoutParams);
		
		// Fast forward button
		RelativeLayout.LayoutParams fastForwardButtonLayoutParams = new RelativeLayout.LayoutParams(
				52,
				47
		);
		fastForwardButton.setVisibility(View.INVISIBLE);
		fastForwardButton.setBackgroundResource(R.drawable.forward_button_drawable);;
		fastForwardButtonLayoutParams.addRule(RelativeLayout.RIGHT_OF, playButton.getId());
		fastForwardButtonLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, playButton.getId());
		navigationLayout.addView(fastForwardButton, fastForwardButtonLayoutParams);
		
		// Fast backward button
		RelativeLayout.LayoutParams fastBackwardButtonLayoutParams = new RelativeLayout.LayoutParams(
				52,
				47
		);
		fastBackwardButton.setVisibility(View.INVISIBLE);
		fastBackwardButton.setBackgroundResource(R.drawable.rewind_button_drawable);
		fastBackwardButtonLayoutParams.addRule(RelativeLayout.LEFT_OF, playButton.getId());
		fastBackwardButtonLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, playButton.getId());
		navigationLayout.addView(fastBackwardButton, fastBackwardButtonLayoutParams);
		
		// Layouts
		navigationLayout.setBackgroundColor(0x00000000);
		//navigationLayout.setVisibility(View.INVISIBLE);
		RelativeLayout.LayoutParams navigationLayoutParams = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.MATCH_PARENT, 
				100
		);
		navigationLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 1);
		navigationLayoutParams.setMargins(uiMarginLeft, uiMarginTop, uiMarginRight, uiMarginBottom);
		
		timelineLayout.setBackgroundColor(0x00000000);
		RelativeLayout.LayoutParams timelineLayoutParams = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.MATCH_PARENT, 
				RelativeLayout.LayoutParams.WRAP_CONTENT
		);
		//timelineLayout.setVisibility(View.INVISIBLE);
		timelineLayout.setMinimumHeight(100);
		timelineLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, 1);
		timelineLayoutParams.setMargins(uiMarginLeft, uiMarginTop, uiMarginRight, uiMarginBottom);
		
		
		
		// Video view
		RelativeLayout.LayoutParams videoViewLayoutParams = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.MATCH_PARENT, 
				RelativeLayout.LayoutParams.MATCH_PARENT
		);
		videoViewLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, 1);
		videoView.setOnCompletionListener(new OnCompletionListener() {
			
			public void onCompletion(MediaPlayer mp) {
				Log.d(logTag, "Media playback completed");
				notifyListenersPlaybackFinished();
			}
		});
		videoView.setOnErrorListener(new OnErrorListener() {
			
			public boolean onError(MediaPlayer mp, int what, int extra) {
				switch (what) {
				case MediaPlayer.MEDIA_ERROR_UNKNOWN:
					Log.e(logTag, "Unknown media in video player");
					break;
				case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
					Log.e(logTag, "Server died in video player");
					break;
				}
				return false;
			}
		});
		videoView.setOnPreparedListener(new OnPreparedListener() {
			
			public void onPrepared(MediaPlayer mp) {
				Log.d(logTag, "Media prepared. Duration is " + videoView.getDuration());
				timelineProgressBar.setMax(videoView.getDuration());
				loadingProgressBar.setVisibility(View.GONE);
			}
		});
		postDelayed(new Runnable() {
			
			public void run() {
				if (videoView.isPlaying()) {
					
					int max = timelineProgressBar.getMax();
					int progress = timelineProgressBar.getProgress();
					
					int secondsElapsed = progress/1000;
					int minutesElapsed = secondsElapsed/60;
					secondsElapsed = secondsElapsed%60;
					
					int secondsRemaining = (max-progress)/1000;
					int minutesRemaining = secondsRemaining/60;
					secondsRemaining = secondsRemaining%60;
					
					//Log.d(logTag, "Updating progress to " + videoView.getCurrentPosition());
					timelineProgressBar.setProgress(videoView.getCurrentPosition());
						
					remainingTimeTextView.setText(String.format("%02d:%02d", new Object[] {minutesRemaining, secondsRemaining}));
					playedTimeTextView.setText(String.format("%02d:%02d", new Object[] {minutesElapsed, secondsElapsed}));
					
				} else {
//					Log.d(logTag, "Video isn't playing, so do nothing.");
				}
				postDelayed(this, 100);
			}
		}, 100);
		
		// Time text views
		RelativeLayout.LayoutParams timePlayedLayoutParams = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT,
				RelativeLayout.LayoutParams.WRAP_CONTENT
		);
		timePlayedLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL, 1);
		timePlayedLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 1);
		playedTimeTextView.setId(3);
		playedTimeTextView.setMinWidth(75);
		playedTimeTextView.setPadding(20, 0, 0, 0);
		playedTimeTextView.setVisibility(View.INVISIBLE);

		RelativeLayout.LayoutParams timeRemainingLayoutParams = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.WRAP_CONTENT,
				RelativeLayout.LayoutParams.WRAP_CONTENT
		);
		timeRemainingLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL, 1);
		timeRemainingLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 1);
		remainingTimeTextView.setId(4);
		remainingTimeTextView.setMinWidth(75);
		remainingTimeTextView.setPadding(0, 0, 20, 0);
		remainingTimeTextView.setVisibility(View.INVISIBLE);
		
		// Progress bar
		timelineProgressBar.setId(2);
		timelineProgressBar.setThumb(getResources().getDrawable(R.drawable.seekbar_thumb));
		timelineProgressBar.setProgressDrawable(getResources().getDrawable(R.drawable.seekbar_background));
		timelineProgressBar.setHorizontalScrollBarEnabled(true);
		timelineProgressBar.setIndeterminate(false);
		timelineProgressBar.setPadding(40, 0, 40, 0);
		timelineProgressBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
			
			public void onStopTrackingTouch(SeekBar arg0) {
				videoView.seekTo(arg0.getProgress());
				videoView.start();
			}
			
			public void onStartTrackingTouch(SeekBar arg0) {
				pause();
			}
			
			public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
			}
		});
		timelineProgressBar.setVisibility(View.INVISIBLE);
		
		RelativeLayout.LayoutParams timelineProgressBarLayoutParams = new RelativeLayout.LayoutParams(
				RelativeLayout.LayoutParams.MATCH_PARENT, 
				RelativeLayout.LayoutParams.WRAP_CONTENT
		);
		timelineProgressBarLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, 1);
		timelineProgressBarLayoutParams.addRule(RelativeLayout.LEFT_OF, remainingTimeTextView.getId());
		timelineProgressBarLayoutParams.addRule(RelativeLayout.RIGHT_OF, playedTimeTextView.getId());

		
		timelineLayout.addView(remainingTimeTextView, timeRemainingLayoutParams);
		timelineLayout.addView(playedTimeTextView, timePlayedLayoutParams);
		timelineLayout.addView(timelineProgressBar, timelineProgressBarLayoutParams);
		
			
		this.addView(videoView, videoViewLayoutParams);
		this.addView(navigationLayout, navigationLayoutParams);
		this.addView(timelineLayout, timelineLayoutParams);
		this.addView(loadingProgressBar, loadingProgressBarLayoutParams);

		setOnTouchListener(new OnTouchListener() {
			public boolean onTouch(View arg0, MotionEvent arg1) {
				// Sometimes two touch events get delivered, even though only one is intended
				// we try to filter those out
				if (!squelchToggles) {
					toggleUI();
					squelchToggles = true;
					postDelayed(new Runnable() {
						
						public void run() {
							squelchToggles = false;
						}
					}, 200);
					return true;
				} else {
					return false;
				}
			}
		});
	}
	
	public void showUI() {
		navigationLayout.setBackgroundColor(0x80000000);
		timelineLayout.setBackgroundColor(0x80000000);
		playButton.setVisibility(View.VISIBLE);
		fastForwardButton.setVisibility(View.VISIBLE);
		fastBackwardButton.setVisibility(View.VISIBLE);
		timelineProgressBar.setVisibility(View.VISIBLE);
		remainingTimeTextView.setVisibility(View.VISIBLE);
		playedTimeTextView.setVisibility(View.VISIBLE);
		state = STATE_UI_ENABLED;
	}
	
	public void hideUI() {
		navigationLayout.setBackgroundColor(0x00000000);
		timelineLayout.setBackgroundColor(0x00000000);
		playButton.setVisibility(View.INVISIBLE);
		fastForwardButton.setVisibility(View.INVISIBLE);
		fastBackwardButton.setVisibility(View.INVISIBLE);
		timelineProgressBar.setVisibility(View.INVISIBLE);
		remainingTimeTextView.setVisibility(View.INVISIBLE);
		playedTimeTextView.setVisibility(View.INVISIBLE);
		state = STATE_UI_DISABLED;
	}
	
	public void toggleUI() {
		AlphaAnimation aa;
		AlphaAnimation aaExt;
		switch (state) {
		case STATE_UI_DISABLED:
			Log.d(logTag, "Showing UI");
			aa = new AlphaAnimation(0, 1);
			aaExt = new AlphaAnimation(0, 1);
			aaExt.setDuration(500);
			notifyListenersUiFadeInStarted(aaExt);
			aa.setAnimationListener(new AnimationListener() {
				
				public void onAnimationStart(Animation animation) {
					showUI();
				}
				
				public void onAnimationRepeat(Animation animation) {
					// TODO Auto-generated method stub
					
				}
				
				public void onAnimationEnd(Animation animation) {
					state = STATE_UI_ENABLED;
				}
			});
			state = STATE_UI_ANIMATING;
			break;
		case STATE_UI_ENABLED:
			Log.d(logTag, "Hiding UI");
			state = STATE_UI_ANIMATING;
			aaExt = new AlphaAnimation(1, 0);
			aaExt.setDuration(500);
			notifyListenersUiFadeOutStarted(aaExt);
			aa = new AlphaAnimation(1, 0);			
			aa.setAnimationListener(new AnimationListener() {
				
				public void onAnimationStart(Animation animation) {
					// TODO Auto-generated method stub
					
				}
				
				public void onAnimationRepeat(Animation animation) {
					// TODO Auto-generated method stub
					
				}
				
				public void onAnimationEnd(Animation animation) {
					state = STATE_UI_DISABLED;
					hideUI();
				}
			});
			break;
		default:
			return;
		}
		aa.setDuration(500);
		navigationLayout.startAnimation(aa);
		timelineLayout.startAnimation(aa);
		playButton.startAnimation(aa);
		fastForwardButton.startAnimation(aa);
		fastBackwardButton.startAnimation(aa);
//		navigationLayout.bringToFront();
//		timelineLayout.bringToFront();
	}
	
	public void setVideoPath(String path) {
		videoView.setVideoPath(path);
	}
	
	public void start() {
		playButton.setBackgroundResource(R.drawable.pause_button_drawable);
		videoView.start();
		notifyListenersPlaybackStarted();
	}
	
	public void pause() {
		playButton.setBackgroundResource(R.drawable.play_button_drawable);
		videoView.pause();
	}
	
}
